package cn.bluedot.tea.filter;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;

import cn.bluedot.common.redis.JedisPoolCacheUtils;
import cn.bluedot.framework.annotations.RequestView;
import cn.bluedot.framework.annotations.ResponseJson;
import cn.bluedot.framework.annotations.Service;
import cn.bluedot.framework.core.ClassScanner;
import cn.bluedot.tea.dao.BaseDao;
import cn.bluedot.tea.filter.changeresponse.AuthCodeResponseWrapper;
import cn.bluedot.tea.pojo.domain.OperationLog;
import cn.bluedot.tea.pojo.domain.User;
import cn.bluedot.tea.util.AddressUtils;
import cn.bluedot.tea.util.ClientInfoUtil;
import cn.bluedot.tea.util.DateUtil;
import redis.clients.jedis.Jedis;

public class OperationLogFilter implements Filter {

	private static Map<String, String> menu = new HashMap<String, String>();
	private static Set<String> url;
	private static Set<String> responseJson = new HashSet<String>();

	public OperationLogFilter() {
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;

		String context = req.getContextPath().trim();
		String requestUri = req.getRequestURI().trim();

		String path = requestUri.replace(context, "").replace(".do", "");
		if (url.contains(path)) {
			String menuName = menu.get(path);
			User user = (User) req.getSession().getAttribute("user");
			if (user == null) {// 用户为空，直接放行，不进行后续步骤
				System.out.println("有一个未登录的操作，访问了需要拥有权限才能访问的接口......");
				chain.doFilter(request, response);
				return;
			}
			String userName = user.getName();
			String email = user.getEmail();
			String method = req.getMethod();
			String requestParam = ClientInfoUtil.getRequestParams(req);
			String ip = ClientInfoUtil.getIPAddress(req);
			OperationLog operationLog = new OperationLog(menuName, userName, email, method, requestParam, ip,
					DateUtil.getDateTime());

			if (responseJson.contains(path)) {// 如果返回的是json则这样获取返回消息和结果
				// 获取返回给客户端的消息
				AuthCodeResponseWrapper responseWrapper = new AuthCodeResponseWrapper((HttpServletResponse) response);
				chain.doFilter(request, responseWrapper);// 放行
				ServletOutputStream out = response.getOutputStream();
				String content = responseWrapper.getTextContent();
				out.write(content.getBytes());
				@SuppressWarnings("unchecked")
				Map<String, Object> msgMap = (Map<String, Object>) JSONObject.parse(content);
				operationLog.setReturnMessage((String) msgMap.get("message"));
				operationLog.setResult((String) msgMap.get("RESULT"));
			} else {
				operationLog.setReturnMessage("");
				operationLog.setResult("转发/重定向");
				chain.doFilter(request, response);// 放行
				System.out.println("处理返回转发和重定向的操作日志.......");
			}
			Thread thread = new LoggerThread(operationLog);
			thread.start();

		} else {
			chain.doFilter(request, response);// 不属于需要权限的操作直接放行
		}
	}

	private class LoggerThread extends Thread {

		OperationLog operationLog;

		public LoggerThread(OperationLog operationLog) {
			this.operationLog = operationLog;
		}

		@SuppressWarnings("unchecked")
		private String getRoleName(String email) {
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("view", "getRoleByEmail");
			param.put("email", email);
			String roleName = "其他";
			try {
				roleName = (String) ((ArrayList<LinkedHashMap<String, Object>>) BaseDao.excuteQuery(param, null)).get(0)
						.get("roleName");
			} catch (Exception e) {
				e.printStackTrace();
			}
			return roleName;
		}

		private String getRoleNameByRedis(String email) {
			Jedis jedis = JedisPoolCacheUtils.getResource();
			String roleName  = jedis.get("roleName:" + email);
			if (roleName == null || "".equals(roleName.trim())) {
				roleName = getRoleName(email);
				jedis.set("roleName:" + email, roleName, "NX", "EX", JedisPoolCacheUtils.EXRP_HOUR);
			}
			jedis.close();
			return roleName;
		}

		@Override
		public void run() {
			operationLog.setRoleName(getRoleNameByRedis(operationLog.getEmail()));// 获取该用户的权限名称
			operationLog.setAddress(AddressUtils.getAddrssessUTF8ByReids(operationLog.getIp()));
			;// 获取该用户的地点
			Map<String, Object> param = new HashMap<String, Object>();

			// 将日志存入数据库当中
			param.put("view", "insertOperationLog");
			param.put("menuName", operationLog.getMenuName());
			param.put("userName", operationLog.getUserName());
			param.put("email", operationLog.getEmail());
			param.put("method", operationLog.getMethod());
			param.put("requestParam", operationLog.getRequestParam());
			param.put("returnMessage", operationLog.getReturnMessage());
			param.put("ip", operationLog.getIp());
			param.put("address", operationLog.getAddress());
			param.put("operationDate", operationLog.getOperationDate());
			param.put("result", operationLog.getResult());
			param.put("roleName", operationLog.getRoleName());
			try {
				BaseDao.excute(param);
			} catch (Exception e) {
				System.out.println("在记录运行日志时出现异常....");
				e.printStackTrace();
			}
		}
	}

	public void init(FilterConfig fConfig) throws ServletException {
		Map<String, Object> param = new HashMap<String, Object>();
		// 根据email查询用户权限
		param.put("view", "getMenuUrl");
		try {
			@SuppressWarnings("unchecked")
			ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) BaseDao
					.excuteQuery(param, null);
			Iterator<LinkedHashMap<String, Object>> it = list.iterator();
			it.next();
			while (it.hasNext()) {
				LinkedHashMap<String, Object> lmap = it.next();
				String key = (String) lmap.get("url");
				String mValue = (String) lmap.get("menuName");
				menu.put(key, mValue);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		url = menu.keySet();
		url.remove("/login");

		// 判断那些接口返回的是json数据
		try {
			List<Class<?>> classList = ClassScanner.scanClasses("cn.bluedot.tea");
			for (Class<?> cls : classList) {
				if (cls.isAnnotationPresent(Service.class)) { // 如果含有Service注解
					Method[] methods = cls.getDeclaredMethods(); // 获取所有方法
					for (Method method : methods) {
						if (method.isAnnotationPresent(ResponseJson.class)) { // 如果有ResponseJson注解
							String value = method.getDeclaredAnnotation(RequestView.class).uri();
							responseJson.add(value);
						}
					}
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
